package com.ktg.mes.unit.other;

import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ktg.common.core.domain.model.SqlResult;
import com.ktg.mes.pro.domain.ProTask;
import com.ktg.mes.wm.domain.WmItemRecptLine;
import com.ktg.mes.wm.domain.WmStockWillOut;
import com.ktg.mes.wm.service.impl.WmItemRecptLineServiceImpl;
import com.ktg.mes.wm.service.impl.WmMaterialStockServiceImpl;
import org.apache.ibatis.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class ZLServiceIml<M extends BaseMapper<T>, T> extends ServiceImpl<M,T> implements ZLService<T> {

    @Autowired
    private ApplicationContext context;

    public ApplicationContext getContext() {
        return context;
    }

    public T findOld(T model){
        throw new RuntimeException(this.getClass().getName()+"  :  需要重写 findOld 方法");
    };

    public List<T> getFromIds(Serializable[] ids){
        throw new RuntimeException(this.getClass().getName()+"  :  需要重写getFromIds方法");
    }




    @Override
    public SqlResult insertSQLModel(T model){
        try {
            Class cls = model.getClass();
            String tableName =  ((TableName)cls.getAnnotation(TableName.class)).value();
            List<SQLListenerModel> list = SQLListener.listenerImpl(tableName+":"+ SQLListenerType.AddBefore.toString());
            SqlResult flag = dealRelation(list,SQLListenerType.AddBefore,null,model);
            if (flag.isSuccess()){
                save(model);
                List<SQLListenerModel> listAfter = SQLListener.listenerImpl(tableName+":"+ SQLListenerType.AddAfter.toString());
                flag = dealRelation(listAfter,SQLListenerType.AddAfter,findOld(model),model);
                flag.setData(model);
            }
            return flag;
        }catch (Exception e){
            LogFactory.getLog(this.getClass()).error(this.getClass().toString()+" :: insertSQLModel",e);
            return SqlResult.error(e.getLocalizedMessage(),model);
        }
    };

    @Override
    public T getById(Serializable id) {
        T item = super.getById(id);
        T copyOne = null;
        try {
            copyOne = (T) item.getClass().newInstance();
            BeanUtils.copyProperties(item,copyOne);
        } catch (Exception e) {
            e.printStackTrace();
            copyOne = item;
        }
        return copyOne;
    }

    @Override
    public SqlResult updateSQLModel(T model){
        try {
            Class cls = model.getClass();
            String tableName =  ((TableName)cls.getAnnotation(TableName.class)).value();
            T object = findOld(model);
            List<SQLListenerModel> list = SQLListener.listenerImpl(tableName+":"+ SQLListenerType.ChangeBefore.toString());
            SqlResult flag = dealRelation(list,SQLListenerType.ChangeBefore,object,model);
            if (flag.isSuccess()){
                getBaseMapper().updateById(model);
                List<SQLListenerModel> listAfter = SQLListener.listenerImpl(tableName+":"+ SQLListenerType.ChangeAfter.toString());
                flag = dealRelation(listAfter,SQLListenerType.ChangeAfter,object,model);
            }
            return flag;
        }catch (Exception e){
            LogFactory.getLog(this.getClass()).error(this.getClass().toString()+" :: updateSQLModel",e);
            return SqlResult.error(e.getLocalizedMessage(),model);
        }
    };

    @Override
    public SqlResult deleteSQLId(Serializable id){
        return deleteSQLModel(getById(id));
    }

    public SqlResult deleteSQLIds(Serializable[] ids) {
        return deleteSQLModelList(getFromIds(ids));
    }


    public SqlResult deleteSQLModelList(List<T> modelList){
        if (modelList != null && modelList.size() > 0){
            for (int i = 0; i < modelList.size(); i++) {
                SqlResult result = deleteSQLModel(modelList.get(i));
                if (!result.isSuccess()){
                    return result;
                }
            }
        }
        return SqlResult.ok(null,null);
    }


    public SqlResult deleteSQLModel(T model){
        try {
            Class cls = model.getClass();
            String tableName =  ((TableName)cls.getAnnotation(TableName.class)).value();
            List<SQLListenerModel> list = SQLListener.listenerImpl(tableName+":"+ SQLListenerType.DeleteBefore.toString());
            SqlResult flag = dealRelation(list,SQLListenerType.DeleteBefore,model,null);
            if (flag.isSuccess()){
                getBaseMapper().deleteById(model);
                List<SQLListenerModel> listAfter = SQLListener.listenerImpl(tableName+":"+ SQLListenerType.DeleteAfter.toString());
                flag = dealRelation(listAfter,SQLListenerType.DeleteAfter,model,null);
            }
            flag.setData(model);
            return flag;
        }catch (Exception e){
            LogFactory.getLog(this.getClass()).error(this.getClass().toString()+" :: deleteSQLId",e);
            return SqlResult.error(e.getLocalizedMessage(),model);
        }
    };


    private SqlResult dealRelation(List<SQLListenerModel> list,SQLListenerType type, T oldObj, T newObj){
        if (list != null && list.size() > 0){
            for (int i = 0; i < list.size(); i++) {
                SQLListenerModel model = list.get(i);
                IService service = getService(getContext(),model.getClassName());
                SqlResult result = null;
                try {
                    result = (SqlResult) model.getMethod().invoke(service,type,oldObj,newObj);
                } catch (Exception e) {
                    SQLListener.findListener();
                    e.printStackTrace();
                    LogFactory.getLog(this.getClass()).error("  "+model.getClassName()+" 提供 ListenerInterface 注解的方法 "+model.getMethod().toString()+" 必须支持 return SqlResult 返回 和 第一位 SQLListenerType,第二位 T old 参数,第三位 T new 参数",e);
                    result = SqlResult.error(e.getLocalizedMessage(),newObj);
                }
                if (!result.isSuccess()){
                    try {
                        //先返回回滚
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    }catch (Exception e){

                    }
                    return result;
                }

            }
        }
        return SqlResult.ok(null,null);
    }

    /***
     *动态初始化Service
     * @return
     */
    @SuppressWarnings("unchecked")
    public IService getService(ApplicationContext context,Class clazz) {
        try {
            // 逻辑处理你需要实例化的类
            String beanName =  clazz.getSimpleName();
            String firstLowerBeanName = beanName.substring(0,1).toLowerCase()+beanName.substring(1,beanName.length());
            Object obj = context.getBean(firstLowerBeanName, clazz);
            if (obj instanceof IService ){
                if (obj instanceof ServiceImpl){
                    return  (IService)obj;
                }else {
                    throw new RuntimeException(" className 需要继承 com.baomidou.mybatisplus.core.mapper.BaseMapper");
                }
            }else {
                throw new RuntimeException(" className 需要继承 com.baomidou.mybatisplus.extension.service.IService");
            }
        } catch (Exception e) {
            System.out.println("请传入正确的 className");
            LogFactory.getLog(this.getClass()).error(this.getClass().toString()+" :: getService(ApplicationContext context,String className) 异常",e);
        }
        return null;
    }


}
